package w.z.x.framework.repository.wrappers;

import cn.hutool.core.util.StrUtil;
import w.z.x.framework.repository.annotations.Mapper;
import w.z.x.framework.repository.interfaces.Func;
import w.z.x.framework.repository.interfaces.Join;
import w.z.x.framework.repository.interfaces.SerialFunction;
import w.z.x.framework.repository.structures.Segment;
import w.z.x.framework.repository.structures.BeanHelper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * lambda查询封装
 *
 * @author 魏祖潇
 */
public class LambdaQueryWrapper<T> extends AbstractWrapper<T, SerialFunction<T, ?>, LambdaQueryWrapper<T>>
        implements Func<LambdaQueryWrapper<T>, SerialFunction<T, ?>>,
        Join<Class, AbstractWrapper<T, String, ?>, LambdaQueryWrapper<T>> {

    private static final String JOINER = "$";

    protected final List<Segment> join = new ArrayList<>();
    protected final List<Segment> orderBy = new ArrayList<>();

    @Override
    public LambdaQueryWrapper<T> orderBy(boolean condition, boolean isAsc, SerialFunction<T, ?>... r) {
        if (condition && r.length > 0) {
            this.orderBy.addAll(Arrays.asList(r).stream()
                    .map(it -> Segment.build(SerialFunction.field(it), "", isAsc))
                    .collect(Collectors.toList())
            );
        }
        return this;
    }

    @Override
    public LambdaQueryWrapper<T> left(Class clazz, String alias, Consumer<AbstractWrapper<T, String, ?>> on) {
        BeanHelper helper = new BeanHelper(clazz);
        Mapper mapper = helper.getMapper();
        if (Objects.isNull(mapper)) {
            throw new RuntimeException("无关联对象表结构映射");
        }
        if (StrUtil.isAllBlank(alias)) {
            alias = JOINER + (this.join.size() + 1);
        }
        Segment left = Segment.build(mapper.value(), "left join", alias);
        AbstractWrapper wrapper = new StringQueryWrapper();
        on.accept(wrapper);
        left.append(wrapper.where.getChildren());
        this.join.add(left);
        return this;
    }

    @Override
    public LambdaQueryWrapper<T> right(Class clazz, String alias, Consumer<AbstractWrapper<T, String, ?>> on) {
        BeanHelper helper = new BeanHelper(clazz);
        Mapper mapper = helper.getMapper();
        if (Objects.isNull(mapper)) {
            throw new RuntimeException("无关联对象表结构映射");
        }
        if (StrUtil.isAllBlank(alias)) {
            alias = JOINER + (this.join.size() + 1);
        }
        Segment right = Segment.build(mapper.value(), "right join", alias);
        AbstractWrapper wrapper = new StringQueryWrapper();
        on.accept(wrapper);
        right.append(wrapper.where.getChildren());
        this.join.add(right);
        return this;
    }

    @Override
    public LambdaQueryWrapper<T> inner(Class clazz, String alias, Consumer<AbstractWrapper<T, String, ?>> on) {
        BeanHelper helper = new BeanHelper(clazz);
        Mapper mapper = helper.getMapper();
        if (Objects.isNull(mapper)) {
            throw new RuntimeException("无关联对象表结构映射");
        }
        if (StrUtil.isAllBlank(alias)) {
            alias = JOINER + (this.join.size() + 1);
        }
        Segment inner = Segment.build(mapper.value(), "inner join", alias);
        AbstractWrapper wrapper = new StringQueryWrapper();
        on.accept(wrapper);
        inner.append(wrapper.where.getChildren());
        this.join.add(inner);
        return this;
    }

    public List<Segment> joinSegment() {
        return this.join;
    }

    public List<Segment> orderBySegment() {
        return this.orderBy;
    }

}
